package org.hit.burkun.obo.dbimport;

import java.io.IOException;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;

import org.hit.burkun.db.DBHelper;
import org.hit.burkun.db.DBTypeConverter;
import org.hit.burkun.obo.dbimport.OboTable.ONTOLOGYNAME;
import org.hit.burkun.obo.model.Dbxref;
import org.hit.burkun.obo.model.OboParser;
import org.hit.burkun.obo.model.Relationship;
import org.hit.burkun.obo.model.Subset;
import org.hit.burkun.obo.model.Synonym;
import org.hit.burkun.obo.model.Term;

public class BaseImport {
	/**
	 * step 1. by OboParser get Term Term2Term Term2Syn Term2xref Term2Subset
	 * Term2Property step 2. use obo table to get the insert line
	 */
	/**
	 * 
	 * @param args
	 */

	public BaseImport(String filePath, DBHelper dbHelper,
			ONTOLOGYNAME tablePreffix, int batchInsertNum) {
		this.myParser = new OboParser(filePath);
		this.dbHelper = dbHelper;
		this.oboTable = new OboTable(tablePreffix);
		this.batchInsertNum = batchInsertNum;
	}

	private OboParser myParser;
	private OboTable oboTable;
	private int batchInsertNum = 1000;
	private DBHelper dbHelper;

	public void importAll() {
		try {
			myParser.parse();
		} catch (IOException e) {
			e.printStackTrace();
		}
		Map<String, String> mapper = importTerm();
		importTerm2Syn(mapper);
		importTerm2Xref(mapper);
		importTerm2Subset(mapper);
		importTerm2Term(mapper);
	}

	private Map<String, String> importTerm() {
		Map<String, String> mapper = new Hashtable<String, String>();
		Collection<Term> terms = myParser.getGoTerms();
		int idCounter = 0;
		LinkedList<String[]> lines = new LinkedList<String[]>();
		for (Term term : terms) {
			idCounter += 1;
			String[] line = oboTable.makeDbTermLine(idCounter, term);
			mapper.put(term.getId(), String.valueOf(idCounter));
			if (line != null)
				lines.add(line);
			batchInsert(lines, oboTable.getTermTbName(), oboTable.getTermC(),
					false);
		}
		batchInsert(lines, oboTable.getTermTbName(), oboTable.getTermC(), true);
		// -- debug
		System.out.println("insert term done!");
		// --
		return mapper;
	}

	private void importTerm2Syn(Map<String, String> mapper) {
		Map<String, Collection<Synonym>> syns = myParser.getTermSynonyms();
		LinkedList<String[]> lines = new LinkedList<String[]>();
		Iterator<Entry<String, Collection<Synonym>>> iter = syns.entrySet()
				.iterator();
		while (iter.hasNext()) {
			Entry<String, Collection<Synonym>> entry = iter.next();
			String termId = entry.getKey();
			Collection<Synonym> coll = entry.getValue();
			for (Synonym syn : coll) {
				String[] line = oboTable
						.makeDbTerm2SynLine(mapper, termId, syn);
				if (line != null)
					lines.add(line);
				batchInsert(lines, oboTable.getTerm2SynTbName(),
						oboTable.getTerm2SynC(), false);
			}
		}
		batchInsert(lines, oboTable.getTerm2SynTbName(),
				oboTable.getTerm2SynC(), true);
		// -- debug
		System.out.println("insert term synonym done!");
		// --
	}

	private void importTerm2Xref(Map<String, String> mapper) {
		Map<String, Collection<Dbxref>> syns = myParser.getTermDbxrefs();
		LinkedList<String[]> lines = new LinkedList<String[]>();
		Iterator<Entry<String, Collection<Dbxref>>> iter = syns.entrySet()
				.iterator();
		while (iter.hasNext()) {
			Entry<String, Collection<Dbxref>> entry = iter.next();
			String termId = entry.getKey();
			Collection<Dbxref> coll = entry.getValue();
			for (Dbxref xref : coll) {
				String[] line = oboTable.makeDbTerm2RefLine(mapper, termId,
						xref);
				if (line != null)
					lines.add(line);
				batchInsert(lines, oboTable.getTerm2refTbName(),
						oboTable.getTerm2refC(), false);
			}
		}
		batchInsert(lines, oboTable.getTerm2refTbName(),
				oboTable.getTerm2refC(), true);
		// -- debug
		System.out.println("insert term xref done!");
		// --
	}

	private void importTerm2Subset(Map<String, String> mapper) {
		Map<String, Collection<Subset>> syns = myParser.getTermSubset();
		LinkedList<String[]> lines = new LinkedList<String[]>();
		Iterator<Entry<String, Collection<Subset>>> iter = syns.entrySet()
				.iterator();
		while (iter.hasNext()) {
			Entry<String, Collection<Subset>> entry = iter.next();
			String termId = entry.getKey();
			Collection<Subset> coll = entry.getValue();
			for (Subset subset : coll) {
				String[] line = oboTable.makeDbTerm2SubsetLine(mapper, termId,
						subset);
				if (line != null)
					lines.add(line);
				batchInsert(lines, oboTable.getTerm2subsetTbName(),
						oboTable.getTerm2subsetC(), false);
			}
		}
		batchInsert(lines, oboTable.getTerm2subsetTbName(),
				oboTable.getTerm2subsetC(), true);
		// -- debug
		System.out.println("insert term subset done!");
		// --
	}

	private void importTerm2Term(Map<String, String> mapper) {
		Map<String, Collection<Relationship>> syns = myParser.getTermRelation();
		LinkedList<String[]> lines = new LinkedList<String[]>();
		Iterator<Entry<String, Collection<Relationship>>> iter = syns
				.entrySet().iterator();
		while (iter.hasNext()) {
			Entry<String, Collection<Relationship>> entry = iter.next();
			String termId = entry.getKey();
			Collection<Relationship> coll = entry.getValue();
			for (Relationship rel : coll) {
				String[] line = oboTable.makeDbTerm2TermLine(mapper, termId,
						rel);
				// 如果mapper中不存在
				if (line != null)
					lines.add(line);
				batchInsert(lines, oboTable.getTerm2termTbName(),
						oboTable.getTerm2termC(), false);
			}
		}
		batchInsert(lines, oboTable.getTerm2termTbName(),
				oboTable.getTerm2termC(), true);
		// -- debug
		System.out.println("insert term 2 term done!");
		// --
	}

	// property

	private int batchInsert(Collection<String[]> lines, String tbName,
			DBTypeConverter converter, boolean isEnd) {
		int count = 0;
		if (isEnd) {
			dbHelper.connectionDB();
			count = dbHelper.insertBatch(tbName, lines, converter);
			lines.clear();
			dbHelper.disconnection();
		} else {
			if (lines.size() == batchInsertNum) {
				dbHelper.connectionDB();
				count = dbHelper.insertBatch(tbName, lines, converter);
				lines.clear();
				dbHelper.disconnection();
			}
		}
		return count;
	}
}
